//
// Created by shiminli on 2024/1/9.
//

#ifndef DDOFFICE_DD_TOKEN_H
#define DDOFFICE_DD_TOKEN_H

#include <iostream>
#include <string>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include "hv/json.hpp"
#include <CommonCrypto/CommonDigest.h>
#include <openssl/sha.h>
#include "number.h"

using json = nlohmann::json;
using namespace std;

class dd_token {
public:
    dd_token(const std::string &secretKey) : secretKey(secretKey) {}
    dd_token() : secretKey("ddoffice") {}

    std::string generateToken(const std::string &userId) {
        time_t expirationTime = time(0) + number::daysToSeconds(7);
//        long expirationTime = std::stol(number::timestamp()) + number::daysToSeconds(7);
        cout << "generateToken.. 过期时间="<<expirationTime<< " user="<<userId<<endl;
        json payload;
        payload["user_id"] = userId;
        payload["exp"] = expirationTime;
        std::string payloadStr = payload.dump();
        // 加密payload

        unsigned char *digest = HMAC(EVP_sha256(), secretKey.c_str(), secretKey.length(),
                                     reinterpret_cast<const unsigned char *>(payloadStr.c_str()), payloadStr.length(),
                                     nullptr, nullptr);
        char mdString[SHA256_DIGEST_LENGTH * 2 + 1];
        std::stringstream ss;
        for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
            ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(digest[i]);
        }
        std::strcpy(mdString, ss.str().c_str());

        return payloadStr + "." + mdString;
    }

    

    bool verifyToken(const std::string &token, std::string &userId) {
        size_t pos = token.find(".");
//        std::string payloadStr = decryptPayload(token.substr(0, pos));
        std::string payloadStr = token.substr(0, pos);
        std::string signature = token.substr(pos + 1);
        json payload = json::parse(payloadStr);
        long currentTime = time(0);

        if (!verifySignature(payloadStr, signature, secretKey)) {
            cout << "verifySignature false" <<endl;
            return false;
        }
        if (payload.contains("exp") && payload["exp"].is_number_integer()) {
            auto expirationTime = payload["exp"].get<int64_t>();
            if (expirationTime < currentTime) {
                cout << "expirationTime false exp="<<expirationTime<< " currentTime="<<currentTime <<endl;
                return false;
            }
        } else {
            return false;
        }

        // 提取userId
        if (payload.contains("user_id") && payload["user_id"].is_string()) {
            userId = payload["user_id"].get<std::string>();
        } else {
            return false;  // userId无效
        }
        return true;
    }

private:
    std::string secretKey;

    bool verifySignature(const std::string &payloadStr, const std::string &signature, const std::string &secretKey) {
        unsigned char *digest = HMAC(EVP_sha256(), secretKey.c_str(), secretKey.length(),
                                     reinterpret_cast<const unsigned char *>(payloadStr.c_str()), payloadStr.length(),
                                     nullptr, nullptr);
        char mdString[SHA256_DIGEST_LENGTH * 2 + 1];
        std::stringstream ss;
        for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
            ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(digest[i]);
        }
        std::strcpy(mdString, ss.str().c_str());
        return signature == mdString;
    }
};


#endif //DDOFFICE_DD_TOKEN_H
